{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6ec1671c",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-4/sub-graph.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239937-lesson-2-sub-graphs)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "3db85080-2299-4885-a2f6-fffa6a09a238",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "# Sub-graphs\n",
    "\n",
    "## Review\n",
    "\n",
    "We're building up to a multi-agent research assistant that ties together all of the modules from this course.\n",
    "\n",
    "We just covered parallelization, which is one important LangGraph controllability topic.\n",
    "\n",
    "## Goals\n",
    "\n",
    "Now, we're [going to cover sub-graphs](https://docs.langchain.com/oss/python/langgraph/use-subgraphs).\n",
    "\n",
    "## State\n",
    "\n",
    "Sub-graphs allow you to create and manage different states in different parts of your graph. \n",
    "\n",
    "This is particularly useful for multi-agent systems, with teams of agents that each have their own state.\n",
    "\n",
    "Let's consider a toy example:\n",
    "\n",
    "* I have a system that accepts logs\n",
    "* It performs two separate sub-tasks by different agents (summarize logs, find failure modes)\n",
    "* I want to perform these two operations in two different sub-graphs.\n",
    "\n",
    "The most critical thing to understand is how the graphs communicate! \n",
    "\n",
    "In short, communication is **done with over-lapping keys**: \n",
    "\n",
    "* The sub-graphs can access `docs` from the parent\n",
    "* The parent can access `summary/failure_report` from the sub-graphs\n",
    "\n",
    "![subgraph.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbb1abf89f2d847ee6f1ff_sub-graph1.png)\n",
    "\n",
    "## Input\n",
    "\n",
    "Let's define a schema for the logs that will be input to our graph."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2954e8c6-496f-4394-b56a-681608bf65da",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install -U  langgraph"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7e413ba-e376-4a5f-a666-2d2154aa6fe2",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "We'll use [LangSmith](https://docs.langchain.com/langsmith/home) for [tracing](https://docs.langchain.com/langsmith/observability-concepts)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "05b26c51",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os, getpass\n",
    "\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"LANGSMITH_API_KEY\")\n",
    "os.environ[\"LANGSMITH_TRACING\"] = \"true\"\n",
    "os.environ[\"LANGSMITH_PROJECT\"] = \"langchain-academy\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3efaf8bb-f675-4c0b-a575-89c7e2987a33",
   "metadata": {},
   "outputs": [],
   "source": [
    "from operator import add\n",
    "from typing_extensions import TypedDict\n",
    "from typing import List, Optional, Annotated\n",
    "\n",
    "# The structure of the logs\n",
    "class Log(TypedDict):\n",
    "    id: str\n",
    "    question: str\n",
    "    docs: Optional[List]\n",
    "    answer: str\n",
    "    grade: Optional[int]\n",
    "    grader: Optional[str]\n",
    "    feedback: Optional[str]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15825627-78c2-4ba0-ad11-95e4afdb771d",
   "metadata": {},
   "source": [
    "## Sub graphs\n",
    "\n",
    "Here is the failure analysis sub-graph, which uses `FailureAnalysisState`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f32986a9-6d11-4646-b2c0-fbae4f524579",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "from langgraph.graph import StateGraph, START, END\n",
    "\n",
    "# Failure Analysis Sub-graph\n",
    "class FailureAnalysisState(TypedDict):\n",
    "    cleaned_logs: List[Log]\n",
    "    failures: List[Log]\n",
    "    fa_summary: str\n",
    "    processed_logs: List[str]\n",
    "\n",
    "class FailureAnalysisOutputState(TypedDict):\n",
    "    fa_summary: str\n",
    "    processed_logs: List[str]\n",
    "\n",
    "def get_failures(state):\n",
    "    \"\"\" Get logs that contain a failure \"\"\"\n",
    "    cleaned_logs = state[\"cleaned_logs\"]\n",
    "    failures = [log for log in cleaned_logs if \"grade\" in log]\n",
    "    return {\"failures\": failures}\n",
    "\n",
    "def generate_summary(state):\n",
    "    \"\"\" Generate summary of failures \"\"\"\n",
    "    failures = state[\"failures\"]\n",
    "    # Add fxn: fa_summary = summarize(failures)\n",
    "    fa_summary = \"Poor quality retrieval of Chroma documentation.\"\n",
    "    return {\"fa_summary\": fa_summary, \"processed_logs\": [f\"failure-analysis-on-log-{failure['id']}\" for failure in failures]}\n",
    "\n",
    "fa_builder = StateGraph(state_schema=FailureAnalysisState,output_schema=FailureAnalysisOutputState)\n",
    "fa_builder.add_node(\"get_failures\", get_failures)\n",
    "fa_builder.add_node(\"generate_summary\", generate_summary)\n",
    "fa_builder.add_edge(START, \"get_failures\")\n",
    "fa_builder.add_edge(\"get_failures\", \"generate_summary\")\n",
    "fa_builder.add_edge(\"generate_summary\", END)\n",
    "\n",
    "graph = fa_builder.compile()\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa83f44c-0bb9-48c6-afec-dad536e608fa",
   "metadata": {},
   "source": [
    "Here is the question summarization sub-grap, which uses `QuestionSummarizationState`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7149000c-ffb6-4834-bd9e-d35b36c524e7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Summarization subgraph\n",
    "class QuestionSummarizationState(TypedDict):\n",
    "    cleaned_logs: List[Log]\n",
    "    qs_summary: str\n",
    "    report: str\n",
    "    processed_logs: List[str]\n",
    "\n",
    "class QuestionSummarizationOutputState(TypedDict):\n",
    "    report: str\n",
    "    processed_logs: List[str]\n",
    "\n",
    "def generate_summary(state):\n",
    "    cleaned_logs = state[\"cleaned_logs\"]\n",
    "    # Add fxn: summary = summarize(generate_summary)\n",
    "    summary = \"Questions focused on usage of ChatOllama and Chroma vector store.\"\n",
    "    return {\"qs_summary\": summary, \"processed_logs\": [f\"summary-on-log-{log['id']}\" for log in cleaned_logs]}\n",
    "\n",
    "def send_to_slack(state):\n",
    "    qs_summary = state[\"qs_summary\"]\n",
    "    # Add fxn: report = report_generation(qs_summary)\n",
    "    report = \"foo bar baz\"\n",
    "    return {\"report\": report}\n",
    "\n",
    "qs_builder = StateGraph(QuestionSummarizationState,output_schema=QuestionSummarizationOutputState)\n",
    "qs_builder.add_node(\"generate_summary\", generate_summary)\n",
    "qs_builder.add_node(\"send_to_slack\", send_to_slack)\n",
    "qs_builder.add_edge(START, \"generate_summary\")\n",
    "qs_builder.add_edge(\"generate_summary\", \"send_to_slack\")\n",
    "qs_builder.add_edge(\"send_to_slack\", END)\n",
    "\n",
    "graph = qs_builder.compile()\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f10a5baf-beab-4927-807a-3e6a5ad3d202",
   "metadata": {},
   "source": [
    "## Adding sub graphs to our parent graph\n",
    "\n",
    "Now, we can bring it all together.\n",
    "\n",
    "We create our parent graph with `EntryGraphState`. \n",
    "\n",
    "And we add our sub-graphs as nodes! \n",
    "\n",
    "```\n",
    "entry_builder.add_node(\"question_summarization\", qs_builder.compile())\n",
    "entry_builder.add_node(\"failure_analysis\", fa_builder.compile())\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "587c8fe1-1ae8-411e-a55d-cac299026646",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Entry Graph\n",
    "class EntryGraphState(TypedDict):\n",
    "    raw_logs: List[Log]\n",
    "    cleaned_logs: Annotated[List[Log], add] # This will be USED BY in BOTH sub-graphs\n",
    "    fa_summary: str # This will only be generated in the FA sub-graph\n",
    "    report: str # This will only be generated in the QS sub-graph\n",
    "    processed_logs:  Annotated[List[int], add] # This will be generated in BOTH sub-graphs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d4da397-310c-4453-969a-e0ae2cc75db8",
   "metadata": {},
   "source": [
    "But, why does `cleaned_logs` have a reducer if it only goes *into* each sub-graph as an input? It is not modified.\n",
    "\n",
    "```\n",
    "cleaned_logs: Annotated[List[Log], add] # This will be USED BY in BOTH sub-graphs\n",
    "```\n",
    "\n",
    "This is because the output state of the subgraphs will contain **all keys**, even if they are unmodified. \n",
    "\n",
    "The sub-graphs are run in parallel.\n",
    "\n",
    "Because the parallel sub-graphs return the same key, it needs to have a reducer like `operator.add` to combine the incoming values from each sub-graph.\n",
    "\n",
    "But, we can work around this by using another concept we talked about before.\n",
    "\n",
    "We can simply create an output state schema for each sub-graph and ensure that the output state schema contains different keys to publish as output.\n",
    "\n",
    "We don't actually need each sub-graph to output `cleaned_logs`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "50092b9b-70c1-41b1-a74a-254683e28ce0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Entry Graph\n",
    "class EntryGraphState(TypedDict):\n",
    "    raw_logs: List[Log]\n",
    "    cleaned_logs: List[Log]\n",
    "    fa_summary: str # This will only be generated in the FA sub-graph\n",
    "    report: str # This will only be generated in the QS sub-graph\n",
    "    processed_logs:  Annotated[List[int], add] # This will be generated in BOTH sub-graphs\n",
    "\n",
    "def clean_logs(state):\n",
    "    # Get logs\n",
    "    raw_logs = state[\"raw_logs\"]\n",
    "    # Data cleaning raw_logs -> docs \n",
    "    cleaned_logs = raw_logs\n",
    "    return {\"cleaned_logs\": cleaned_logs}\n",
    "\n",
    "entry_builder = StateGraph(EntryGraphState)\n",
    "entry_builder.add_node(\"clean_logs\", clean_logs)\n",
    "entry_builder.add_node(\"question_summarization\", qs_builder.compile())\n",
    "entry_builder.add_node(\"failure_analysis\", fa_builder.compile())\n",
    "\n",
    "entry_builder.add_edge(START, \"clean_logs\")\n",
    "entry_builder.add_edge(\"clean_logs\", \"failure_analysis\")\n",
    "entry_builder.add_edge(\"clean_logs\", \"question_summarization\")\n",
    "entry_builder.add_edge(\"failure_analysis\", END)\n",
    "entry_builder.add_edge(\"question_summarization\", END)\n",
    "\n",
    "graph = entry_builder.compile()\n",
    "\n",
    "from IPython.display import Image, display\n",
    "\n",
    "# Setting xray to 1 will show the internal structure of the nested graph\n",
    "display(Image(graph.get_graph(xray=1).draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "17af1254-4e75-4349-9a79-295f4ec95016",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'raw_logs': [{'id': '1',\n",
       "   'question': 'How can I import ChatOllama?',\n",
       "   'answer': \"To import ChatOllama, use: 'from langchain_community.chat_models import ChatOllama.'\"},\n",
       "  {'id': '2',\n",
       "   'question': 'How can I use Chroma vector store?',\n",
       "   'answer': 'To use Chroma, define: rag_chain = create_retrieval_chain(retriever, question_answer_chain).',\n",
       "   'grade': 0,\n",
       "   'grader': 'Document Relevance Recall',\n",
       "   'feedback': 'The retrieved documents discuss vector stores in general, but not Chroma specifically'}],\n",
       " 'cleaned_logs': [{'id': '1',\n",
       "   'question': 'How can I import ChatOllama?',\n",
       "   'answer': \"To import ChatOllama, use: 'from langchain_community.chat_models import ChatOllama.'\"},\n",
       "  {'id': '2',\n",
       "   'question': 'How can I use Chroma vector store?',\n",
       "   'answer': 'To use Chroma, define: rag_chain = create_retrieval_chain(retriever, question_answer_chain).',\n",
       "   'grade': 0,\n",
       "   'grader': 'Document Relevance Recall',\n",
       "   'feedback': 'The retrieved documents discuss vector stores in general, but not Chroma specifically'}],\n",
       " 'fa_summary': 'Poor quality retrieval of Chroma documentation.',\n",
       " 'report': 'foo bar baz',\n",
       " 'processed_logs': ['failure-analysis-on-log-2',\n",
       "  'summary-on-log-1',\n",
       "  'summary-on-log-2']}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Dummy logs\n",
    "question_answer = Log(\n",
    "    id=\"1\",\n",
    "    question=\"How can I import ChatOllama?\",\n",
    "    answer=\"To import ChatOllama, use: 'from langchain_community.chat_models import ChatOllama.'\",\n",
    ")\n",
    "\n",
    "question_answer_feedback = Log(\n",
    "    id=\"2\",\n",
    "    question=\"How can I use Chroma vector store?\",\n",
    "    answer=\"To use Chroma, define: rag_chain = create_retrieval_chain(retriever, question_answer_chain).\",\n",
    "    grade=0,\n",
    "    grader=\"Document Relevance Recall\",\n",
    "    feedback=\"The retrieved documents discuss vector stores in general, but not Chroma specifically\",\n",
    ")\n",
    "\n",
    "raw_logs = [question_answer,question_answer_feedback]\n",
    "graph.invoke({\"raw_logs\": raw_logs})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a8e241ae",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "9192d228-4d3d-4fb0-8bea-26772c3d2e0b",
   "metadata": {},
   "source": [
    "## LangSmith\n",
    "\n",
    "Let's look at the LangSmith trace:\n",
    "\n",
    "https://smith.langchain.com/public/f8f86f61-1b30-48cf-b055-3734dfceadf2/r"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15e836d4",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
